package org.jboss.resteasy.cdi;
import org.jboss.resteasy.cdi.i18n.LogMessages;
import org.jboss.resteasy.cdi.i18n.Messages;
import org.jboss.resteasy.core.InjectorFactoryImpl;
import org.jboss.resteasy.core.ValueInjector;
import org.jboss.resteasy.spi.ConstructorInjector;
import org.jboss.resteasy.spi.InjectorFactory;
import org.jboss.resteasy.spi.MethodInjector;
import org.jboss.resteasy.spi.PropertyInjector;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.metadata.Parameter;
import org.jboss.resteasy.spi.metadata.ResourceClass;
import org.jboss.resteasy.spi.metadata.ResourceConstructor;
import org.jboss.resteasy.spi.metadata.ResourceLocator;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Map;
import java.util.Set;
/**
* @author Jozef Hartinger
*/
@SuppressWarnings("rawtypes")
public class CdiInjectorFactory implements InjectorFactory
{
public static final String BEAN_MANAGER_ATTRIBUTE_PREFIX = "org.jboss.weld.environment.servlet.";
private BeanManager manager;
private InjectorFactory delegate = new InjectorFactoryImpl();
private ResteasyCdiExtension extension;
private Map<Class<?>, Type> sessionBeanInterface;
public CdiInjectorFactory()
{
this.manager = lookupBeanManager();
this.extension = lookupResteasyCdiExtension();
sessionBeanInterface = extension.getSessionBeanInterface();
}
@Override
public ValueInjector createParameterExtractor(Parameter parameter, ResteasyProviderFactory providerFactory)
{
return delegate.createParameterExtractor(parameter, providerFactory);
}
@Override
public MethodInjector createMethodInjector(ResourceLocator method, ResteasyProviderFactory factory)
{
return delegate.createMethodInjector(method, factory);
}
@Override
public PropertyInjector createPropertyInjector(ResourceClass resourceClass, ResteasyProviderFactory providerFactory)
{
return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, providerFactory), resourceClass.getClazz(), sessionBeanInterface, manager);
}
@Override
public ConstructorInjector createConstructor(ResourceConstructor constructor, ResteasyProviderFactory providerFactory)
{
Class<?> clazz = constructor.getConstructor().getDeclaringClass();
ConstructorInjector injector = cdiConstructor(clazz);
if (injector != null) return injector;
LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz));
return delegate.createConstructor(constructor, providerFactory);
}
@Override
public ConstructorInjector createConstructor(Constructor constructor, ResteasyProviderFactory factory)
{
Class<?> clazz = constructor.getDeclaringClass();
ConstructorInjector injector = cdiConstructor(clazz);
if (injector != null) return injector;
LogMessages.LOGGER.debug(Messages.MESSAGES.noCDIBeansFound(clazz));
return delegate.createConstructor(constructor, factory);
}
protected ConstructorInjector cdiConstructor(Class<?> clazz)
{
if (!manager.getBeans(clazz).isEmpty())
{
LogMessages.LOGGER.debug(Messages.MESSAGES.usingCdiConstructorInjector(clazz));
return new CdiConstructorInjector(clazz, manager);
}
if (sessionBeanInterface.containsKey(clazz))
{
Type intfc = sessionBeanInterface.get(clazz);
LogMessages.LOGGER.debug(Messages.MESSAGES.usingInterfaceForLookup(intfc, clazz));
return new CdiConstructorInjector(intfc, manager);
}
return null;
}
public PropertyInjector createPropertyInjector(Class resourceClass, ResteasyProviderFactory factory)
{
return new CdiPropertyInjector(delegate.createPropertyInjector(resourceClass, factory), resourceClass, sessionBeanInterface, manager);
}
public ValueInjector createParameterExtractor(Class injectTargetClass, AccessibleObject injectTarget, Class type, Type genericType, Annotation[] annotations, ResteasyProviderFactory factory)
{
return delegate.createParameterExtractor(injectTargetClass, injectTarget, type, genericType, annotations, factory);
}
public ValueInjector createParameterExtractor(Class injectTargetClass, AccessibleObject injectTarget, Class type,
Type genericType, Annotation[] annotations, boolean useDefault, ResteasyProviderFactory factory)
{
return delegate.createParameterExtractor(injectTargetClass, injectTarget, type, genericType, annotations, useDefault, factory);
}
/**
* Do a lookup for BeanManager instance. JNDI and ServletContext is searched.
*
* @return BeanManager instance
*/
protected BeanManager lookupBeanManager()
{
BeanManager beanManager = null;
// Do a lookup for BeanManager in JNDI (this is the only *portable* way)
beanManager = lookupBeanManagerInJndi("java:comp/BeanManager");
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaComp());
return beanManager;
}
// Do a lookup for BeanManager at an alternative JNDI location (workaround for WELDINT-19)
beanManager = lookupBeanManagerInJndi("java:app/BeanManager");
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerAtJavaApp());
return beanManager;
}
beanManager = lookupBeanManagerCDIUtil();
if(beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerViaCDI());
return beanManager;
}
beanManager = lookupBeanManagerViaServletContext();
if(beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
throw new RuntimeException(Messages.MESSAGES.unableToLookupBeanManager());
}
private BeanManager lookupBeanManagerInJndi(String name)
{
try
{
InitialContext ctx = new InitialContext();
LogMessages.LOGGER.debug(Messages.MESSAGES.doingALookupForBeanManager(name));
return (BeanManager) ctx.lookup(name);
}
catch (NamingException e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToObtainBeanManager(name));
return null;
}
catch (NoClassDefFoundError ncdfe)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToPerformJNDILookups());
return null;
}
}
private static BeanManager lookupBeanManagerViaServletContext()
{
BeanManager beanManager = null;
try
{
// Look for BeanManager in ServletContext
ServletContext servletContext = ResteasyProviderFactory.getContextData(ServletContext.class);
// null check for RESTEASY-1009
if (servletContext != null)
{
beanManager = (BeanManager) servletContext.getAttribute(BEAN_MANAGER_ATTRIBUTE_PREFIX + BeanManager.class.getName());
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
// Look for BeanManager in ServletContext (the old attribute name for backwards compatibility)
beanManager = (BeanManager) servletContext.getAttribute(BeanManager.class.getName());
if (beanManager != null)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.foundBeanManagerInServletContext());
return beanManager;
}
}
}
catch (NoClassDefFoundError e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindServletContextClass(), e);
}
catch (Exception e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpServletContext(), e);
}
return beanManager;
}
public static BeanManager lookupBeanManagerCDIUtil()
{
BeanManager bm = null;
try
{
bm = CDI.current().getBeanManager();
}
catch (NoClassDefFoundError e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.unableToFindCDIClass(), e);
}
catch (Exception e)
{
LogMessages.LOGGER.debug(Messages.MESSAGES.errorOccurredLookingUpViaCDIUtil(), e);
}
return bm;
}
/**
* Lookup ResteasyCdiExtension instance that was instantiated during CDI bootstrap
*
* @return ResteasyCdiExtension instance
*/
private ResteasyCdiExtension lookupResteasyCdiExtension()
{
Set<Bean<?>> beans = manager.getBeans(ResteasyCdiExtension.class);
Bean<?> bean = manager.resolve(beans);
if (bean == null)
{
throw new IllegalStateException(Messages.MESSAGES.unableToObtainResteasyCdiExtension());
}
CreationalContext<?> context = manager.createCreationalContext(bean);
return (ResteasyCdiExtension) manager.getReference(bean, ResteasyCdiExtension.class, context);
}
}